﻿using System;
using System.Collections.Concurrent;
using System.IO.Ports;
using System.Threading;
using Iot.Shared.Helper;
using Microsoft.Extensions.Logging;

namespace Communication.DataReceivedEvent.COM;

public class SerialPortEvent(SerialPortEventInfo info, ILogger logger) : IDataReceivedEvent
{
    //private readonly Channel<byte[]> _channel = Channel.CreateBounded<byte[]>(new BoundedChannelOptions(100)
    //{ FullMode = BoundedChannelFullMode.DropOldest });

    /// <summary>
    ///     初始化串行端口
    /// </summary>
    private readonly SerialPort _port = new(info.PortName, info.BaudRate, info.Parity, info.DataBits, info.StopBits)
        { ReadBufferSize = info.ReadBufferSize, WriteBufferSize = info.WriteBufferSize };


    private readonly BlockingCollection<byte[]> _queue = new(100);


    /// <summary>
    ///     回调函数
    /// </summary>
    private Action<byte[]?>? _action;


    public ILogger Logger => logger;

    public bool Connected { get; private set; }

    public void Close()
    {
        _port.Dispose();
    }

    public void Dispose()
    {
        Close();
        GC.SuppressFinalize(this);
    }


    public bool Start(Action<byte[]?> action)
    {
        _action = action;
        if (Connected) return Connected;
        _port.Open();
        _port.DataReceived += DataReceived;
        ThreadHelper.Run(Run, ThreadPriority.Normal, true, "串口总线数据接收线程启动失败", logger);
        Connected = true;
        return Connected;
    }

    public string ToString(string? format, IFormatProvider? formatProvider)
    {
        return info.ToString(format, formatProvider);
    }

    private void DataReceived(object sender, SerialDataReceivedEventArgs e)
    {
        var count = _port.BytesToRead;
        if (count <= 0) return;
        var data = new byte[count];
        var len = _port.Read(data, 0, count);
        if (len <= 0) return;
        _queue.TryAdd(data);
        // _channel.Writer.TryWrite(data);
    }

    private void Run()
    {
        try
        {
            while (Connected)
            {
                //using var cts = new CancellationTokenSource(TimeSpan.FromMilliseconds(1000));
                //byte[]? data = null;
                //try
                //{
                //    data = await _channel.Reader.ReadAsync(cts.Token);
                //}
                //catch (Exception e)
                //{
                //    Console.WriteLine(e);
                //}
                _queue.TryTake(out var data, 1000);
                _action?.Invoke(data);
            }
        }
        catch (Exception e)
        {
            Console.WriteLine(e);
        }
    }
}